package com.sky.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 查询性能监控切面
 * 用于监控数据库查询性能，识别慢查询
 */
@Aspect
@Component
@Slf4j
public class QueryPerformanceAspect {

    // 慢查询阈值（毫秒）
    private static final long SLOW_QUERY_THRESHOLD = 1000;
    
    // 查询统计信息
    private final ConcurrentHashMap<String, QueryStats> queryStats = new ConcurrentHashMap<>();

    /**
     * 监控Mapper层的查询方法
     */
    @Around("execution(* com.sky.mapper.*.*(..))")
    public Object monitorQueryPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getDeclaringType().getSimpleName() + "." + joinPoint.getSignature().getName();
        long startTime = System.currentTimeMillis();
        
        try {
            // 执行查询
            Object result = joinPoint.proceed();
            
            // 计算执行时间
            long executionTime = System.currentTimeMillis() - startTime;
            
            // 更新统计信息
            updateQueryStats(methodName, executionTime, true);
            
            // 记录慢查询
            if (executionTime > SLOW_QUERY_THRESHOLD) {
                log.warn("慢查询警告: {} 执行时间: {}ms, 参数: {}", 
                    methodName, executionTime, joinPoint.getArgs());
            }
            
            return result;
            
        } catch (Exception e) {
            // 更新统计信息（失败）
            updateQueryStats(methodName, System.currentTimeMillis() - startTime, false);
            
            log.error("查询执行异常: {}, 参数: {}", methodName, joinPoint.getArgs(), e);
            throw e;
        }
    }

    /**
     * 更新查询统计信息
     */
    private void updateQueryStats(String methodName, long executionTime, boolean success) {
        queryStats.computeIfAbsent(methodName, k -> new QueryStats())
                 .updateStats(executionTime, success);
    }

    /**
     * 获取查询统计信息
     */
    public ConcurrentHashMap<String, QueryStats> getQueryStats() {
        return queryStats;
    }

    /**
     * 重置统计信息
     */
    public void resetStats() {
        queryStats.clear();
    }

    /**
     * 查询统计信息内部类
     */
    public static class QueryStats {
        private final AtomicLong totalCount = new AtomicLong(0);
        private final AtomicLong successCount = new AtomicLong(0);
        private final AtomicLong totalTime = new AtomicLong(0);
        private final AtomicLong maxTime = new AtomicLong(0);
        private final AtomicLong minTime = new AtomicLong(Long.MAX_VALUE);

        public void updateStats(long executionTime, boolean success) {
            totalCount.incrementAndGet();
            if (success) {
                successCount.incrementAndGet();
            }
            
            totalTime.addAndGet(executionTime);
            
            // 更新最大执行时间
            long currentMax = maxTime.get();
            while (executionTime > currentMax && !maxTime.compareAndSet(currentMax, executionTime)) {
                currentMax = maxTime.get();
            }
            
            // 更新最小执行时间
            long currentMin = minTime.get();
            while (executionTime < currentMin && !minTime.compareAndSet(currentMin, executionTime)) {
                currentMin = minTime.get();
            }
        }

        public long getTotalCount() { return totalCount.get(); }
        public long getSuccessCount() { return successCount.get(); }
        public long getTotalTime() { return totalTime.get(); }
        public long getMaxTime() { return maxTime.get(); }
        public long getMinTime() { return minTime.get() == Long.MAX_VALUE ? 0 : minTime.get(); }
        public double getAvgTime() { 
            long count = totalCount.get(); 
            return count > 0 ? (double) totalTime.get() / count : 0; 
        }
        public double getSuccessRate() { 
            long total = totalCount.get(); 
            return total > 0 ? (double) successCount.get() / total : 0; 
        }
    }
}











